package svclogpubsub

import (
	"fmt"
	"sync/atomic"

	"starsine.cn/appTpl/cmn"
	"starsine.cn/appTpl/cmn/logs"
	"starsine.cn/appTpl/cmn/pubsub"
	"starsine.cn/appTpl/svccenter/registry/grpc/scregistryproto"
	"starsine.cn/appTpl/svclog/src/fe/openapi"
	"starsine.cn/appTpl/svclog/src/fe/ws-server/wsserver"
	"starsine.cn/appTpl/svcregistry"
	"starsine.cn/appTpl/svcregistry/grpc/client"
	"starsine.cn/appTpl/svcregistry/grpc/svcregistryproto"
)

func SubSvcUpdate() {
	myID := svcregistry.GetInstanceID()
	topic := fmt.Sprintf("svc-update?instance-id=*;action=*")
	client.SubSvcUpdate(&scregistryproto.SubSvcUpdateReq{
		InstanceID: myID,
		Topic:      topic,
		IsAlways:   true,
	})
	logs.Infof("%s sub svc update, topic=%s", myID, topic)

	cmn.GetEvntEmiter().On("svc-update", func(params ...interface{}) {
		in := params[0].(*svcregistryproto.PubSvcUpdateReq)
		pm := pubsub.TopicParse(in.Topic)
		logs.Debugf("on svc-update, get params: %+v", pm)

		GetPubSub().Event(in.Topic, []openapi.SvcUpdateInfo{
			{
				InstanceID: in.Data.InstanceID,
				Action:     in.Data.Action,
			},
		})
	})
}

func UnSubSvcUpdate() {
	myID := svcregistry.GetInstanceID()
	topic := fmt.Sprintf("svc-update?instance-id=*;action=*")
	client.UnSubSvcUpdate(&scregistryproto.SubSvcUpdateReq{
		InstanceID: myID,
		Topic:      topic,
		IsAlways:   true,
	})
	logs.Infof("%s unsub svc update, topic=%s", myID, topic)
}

type FeSubscriber struct {
	conn *wsserver.WsServer
	sn   atomic.Int32
}

func (p *FeSubscriber) Send(topic string, content interface{}) error {
	pm := pubsub.TopicParse(topic)

	if pm["topic"] == "svc-update" {
		err := p.conn.SendMessage(&openapi.WsSvcUpdatePubReq{
			MsgHead: openapi.WsHead{
				InstanceID:  svcregistry.GetInstanceID(),
				ResOrReq:    "req",
				RequestType: "svc-update-pub",
				SerialNum:   p.sn.Add(1),
				Message:     fmt.Sprintf("svc update ok"),
				Status:      "ok",
			},
			Data: openapi.SvcUpdatePubReqData{
				Topic:         topic,
				SvcUpdateInfo: content.([]openapi.SvcUpdateInfo),
			},
		})

		if err != nil {
			logs.Warnf("FeSubscriber Send(topic:%s, content:%+v) fail, err: %s", topic, content, err)
		} else {
			logs.Warnf("FeSubscriber Send(topic:%s, content:%+v) ok", topic, content)
		}
		return err
	}

	return fmt.Errorf("FeSubscriber send unknown topic(%s)", topic)
}

func (p *FeSubscriber) GetInstanceID() string {
	return fmt.Sprintf("%p", p.conn)
}

func FeSubSvcUpdate(conn *wsserver.WsServer) {
	c := pubsub.Client{
		IsAlways: true,
		IClient: &FeSubscriber{
			conn: conn,
		},
	}
	topic := fmt.Sprintf("svc-update?instance-id=*;action=*")
	if GetPubSub().IsTopicClientExist(topic, c) {
		logs.Warnf("FeSubSvcUpdate(topic=%s, conn=%s) had subscribered", topic, c.GetInstanceID())
		return
	}

	GetPubSub().Sub(topic, c)
	SubSvcUpdate()
}

func FeUnSubSvcUpdate(conn *wsserver.WsServer) {
	c := pubsub.Client{
		IsAlways: true,
		IClient: &FeSubscriber{
			conn: conn,
		},
	}
	topic := fmt.Sprintf("svc-update?instance-id=*;action=*")
	if !GetPubSub().IsTopicExist(topic) {
		logs.Warnf("FeUnSubSvcUpdate(topic=%s, conn=%s) but topic not exist.", topic, c.GetInstanceID())
		return
	}
	// if !GetPubSub().IsTopicClientExist(topic, c) {
	// 	logs.Warnf("FeUnSubSvcUpdate(topic=%s, conn=%s) but topic client not exist.", topic, c.GetInstanceID())
	// 	return
	// }
	GetPubSub().UnSub(topic, c.GetInstanceID())

	if !GetPubSub().IsTopicExist(topic) {
		UnSubSvcUpdate()
		logs.Warnf("FeUnSubSvcUpdate(topic=%s, conn=%s) UnSubSvcUpdate", topic, c.GetInstanceID())
		return
	}
}
